home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Maclife 157
/
MACLIFE157-2001-09.ISO.7z
/
MACLIFE157-2001-09.ISO
/
Linux
/
MacOS Tools
/
BootX 1.2.2
/
Sources
/
src
/
common
/
boot.c
next >
Wrap
Text File
|
2001-07-23
|
43KB
|
1,569 lines
/* BootX
*
* Written by Benjamin Herrenschmidt
*
* portions of this code from InfiniteOS boot loader by <...>, portions from
* quik by Paul Mackerras.
*
* GPL....
*
* This file contains all the code involved in loading kernels, ramdisks,
* preparing the boot environement and doing the actual boot.
* It's shared between BootX and miBoot
*
*/
#include <Types.h>
#include <NameRegistry.h>
#include <Processes.h>
#include <ShutDown.h>
#include <Files.h>
#include <Devices.h>
#include <Errors.h>
#include <LowMem.h>
#include <Gestalt.h>
#include "boot.h"
#include "uLibc.h"
#include "debug_text.h"
#include "zlib.h"
#include "elf_loader_defs.h"
#include "extract_dev_tree.h"
#include "bootx.h"
#include "LowLevelBoot.h"
#include "rs6000.h"
#include "boot.h"
/* This should be exported by someone else */
extern dt_context* dct;
extern Boolean g_arch_PCI;
/* --- Local definitions */
#define DEBUG 1
#define get_16be(x) (*(unsigned short *)(x))
#define get_32be(x) (*(unsigned long *)(x))
#define NAME_REGISTRY_MAX_SIZE (128UL * 1024UL) // 128Kb: Size pre-allocated for holding name registry
#define BOOT_KERNEL_STACK_SIZE 65536 // initial stack
#define TEMP_BUFFER_SIZE 1024
/* Alignement macros */
#define PAGE_ALIGN(x) ((((UInt32)(x)) + g_page_size - 1) & (-g_page_size))
#define LINE_ALIGN(x) ((((UInt32)(x)) + 32 - 1) & (-32))
#define BI_OFFSET(x) (offsets[x] - offsets[offset_bootinfo])
/* MacOS nanokernel data structures */
#define MACOS_MEMMAP_PTR_ADDR 0x5FFFEFF0
#define MACOS_MEMMAP_SIZE_ADDR 0x5FFFEFF6
#define MACOS_MEMMAP_BANK_0FFSET 48
#define kFinderSig 'FNDR'
#define kSystemType 'MACS'
/* Glue resources */
enum {
code_boot_glue68k = 128,
code_boot_gluePrePPC = 129,
code_boot_glueStrapPPC = 130,
code_boot_glueBurgundy = 131
};
/* Indexes in offset array */
enum
{
offset_kernel = 0, /* kernel itself, offset 0 */
offset_stack, /* boot stack */
offset_bootinfo, /* boot_info */
offset_arguments, /* args line */
offset_color_map, /* colormap setup by bootx */
offset_device_tree, /* device tree */
offset_ramdisk, /* optional ramdisk */
offset_unmangler, /* unmangler (may be moved higher) */
offset_count
};
/* FIXME ! Page size is currently hard coded. */
static UInt32 g_page_size = 4096;
/* Large enough for what we need for check_xxx routines */
static s_temp_buffer[TEMP_BUFFER_SIZE];
/* --- Static functions prototypes --- */
#if BOOTX_ENV == BOOTX_ENV_RAW
UInt8* get_physical(void* ptr);
#else
static UInt8* get_physical(void* ptr);
#endif
static OSErr gunzip(void *dst, unsigned int dstlen, unsigned char *src, unsigned int *lenp);
static OSErr check_elf_kernel(boot_kernel_desc_t* in_desc);
static OSErr build_pci_device_tree(Ptr devTree, UInt32 *outDevTreeSize, UInt32 *outDispRegOff);
static OSErr make_resident(void* ptr, unsigned long size, Boolean contiguous);
static void* load_bootstrap(UInt32 mapSize, UInt32** outMapBegin,UInt32 *outTotalSize);
static Ptr alloc_high_mem(unsigned long count);
static void setup_basic_bootinfo(boot_infos_t* bi, UInt32 *out_load_base);
static OSErr make_kernel_map(Ptr base, UInt32 total_size, UInt32 **out_map, UInt32 *out_size);
static void build_memory_map(boot_infos_t* bi);
static UInt32 get_temp_page(UInt32 *cur_temp, UInt32 *used_map, UInt32 used_size);
static void make_kernel_copymap(UInt32* map, UInt32 map_size, UInt32 *map_loc, UInt32 dest_base, UInt32 *temp_page);
static OSErr send_restart_to_finder(void);
static OSErr find_finder_process(ProcessSerialNumberPtr processSN);
static OSErr do_load_glues(Ptr *low_68k_glue, Ptr *low_PPC_glue);
static void add_l2cr_property(UInt32 l2cr_value);
static void check_burgundy_patch(void);
static void debug_checkpoint(void);
static OSErr file_read(boot_file_t *file, UInt32 offset, void *buffer, UInt32 *size);
static OSErr file_open(boot_file_t *file);
static void file_close(boot_file_t *file);
static int my_sscanfld(char *s, unsigned long int *v);
/* --- Implementation --- */
OSErr
file_read(boot_file_t *file, UInt32 offset, void *buffer, UInt32 *size)
{
ParamBlockRec pb;
OSErr err;
#if BOOTX_USES_FILES
pb.ioParam.ioRefNum = file->rn;
pb.ioParam.ioBuffer = (Ptr)buffer;
pb.ioParam.ioReqCount = (long)*size;
pb.ioParam.ioPosMode = fsFromStart;
pb.ioParam.ioPosOffset = (long)offset;
err = PBReadSync(&pb);
*size = (UInt32)pb.ioParam.ioActCount;
#else
// -- NOT YET IMPLEMENTED --
#endif
return err;
}
OSErr
file_open(boot_file_t *file)
{
#if BOOTX_USES_FILES
HParamBlockRec pb;
OSErr err;
pb.ioParam.ioMisc = NULL;
pb.fileParam.ioFVersNum = 0;
pb.fileParam.ioNamePtr = file->spec.name;
pb.fileParam.ioVRefNum = file->spec.vRefNum;
pb.fileParam.ioDirID = file->spec.parID;
pb.ioParam.ioPermssn = fsRdPerm;
err = PBHOpenDFSync(&pb);
if (err == paramErr)
err = PBHOpenSync(&pb);
file->rn = pb.ioParam.ioRefNum;
GetEOF(file->rn, (long *)&file->size);
return err;
#else
return (file->rn == -1) notOpenErr : noErr;
#endif
}
void
file_close(boot_file_t *file)
{
#if BOOTX_USES_FILES
/* FIXME: use PBCloseSync */
FSClose(file->rn);
file->rn = -1;
#endif
}
/* I don't want to include the MSL Standard C librairies, just to scan an offset
in the Mach Kernel Image file */
int my_sscanfld(char *s, unsigned long int *v)
{
char *c, *pos;
unsigned long int i, j;
c = s;
while (*c && (*c < '0' || *c > '9'))
c++;
if (!*c)
return(0);
pos = c;
while (*c >= '0' && *c <= '9')
c++;
i = 0;
for (j = 1, c--; c >= pos; c--) {
i += ((unsigned long int) (*c - '0')) * j;
j *= 10;
}
if (v) {
*v = i;
return(1);
}
return(0);
}
static check_one_key(KeyMap map, UInt8 key_code)
{
return ((((UInt8 *)map)[key_code >> 3] >> (key_code & 7)) & 1);
}
void
debug_checkpoint(void)
{
KeyMap keys;
do {
GetKeys(keys);
if (!check_one_key(keys, 0x3a))
break;
} while(true);
}
static void *
zalloc(void *, unsigned int items, unsigned int size)
{
Ptr p = NewPtr(((SInt32)size) * (SInt32)items);
if (!p)
dt_printf(dct, "#zalloc(%d bytes) failed (err: %d) !",
(size*items), MemError());
return p;
}
static void
zfree(void *, void *addr, unsigned int)
{
if (addr)
DisposePtr(addr);
}
#define HEAD_CRC 2
#define EXTRA_FIELD 4
#define ORIG_NAME 8
#define COMMENT 0x10
#define RESERVED 0xe0
#define DEFLATED 8
OSErr
gunzip(void *dst, unsigned int dstlen, unsigned char *src, unsigned int *lenp)
{
z_stream s;
int r, i, flags;
/* skip header */
i = 10;
flags = src[3];
if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
dt_printf(dct, "#gunzip: bad gzipped data¥n");
return -1;
}
if ((flags & EXTRA_FIELD) != 0)
i = 12 + src[10] + (src[11] << 8);
if ((flags & ORIG_NAME) != 0)
while (src[i++] != 0)
;
if ((flags & COMMENT) != 0)
while (src[i++] != 0)
;
if ((flags & HEAD_CRC) != 0)
i += 2;
if (i >= *lenp) {
dt_printf(dct, "#gunzip: ran out of data in header¥n");
return -1;
}
s.zalloc = zalloc;
s.zfree = zfree;
r = inflateInit2(&s, -MAX_WBITS);
if (r != Z_OK) {
dt_printf(dct, "#gunzip: inflateInit2 returned %d¥n", r);
return -1;
}
s.next_in = src + i;
s.avail_in = *lenp - i;
s.next_out = dst;
s.avail_out = dstlen;
r = inflate(&s, Z_FINISH);
if (r != Z_OK && r != Z_STREAM_END) {
dt_printf(dct, "#gunzip: inflate returned %d¥n", r);
return -1;
}
*lenp = (unsigned int)(s.next_out - (unsigned char *) dst);
inflateEnd(&s);
return noErr;
}
OSErr
build_pci_device_tree(Ptr devTree, UInt32 *outDevTreeSize, UInt32 *outDispRegOff)
{
OSErr err;
err = noErr;
*outDevTreeSize = NAME_REGISTRY_MAX_SIZE;
/* FIXME: We shoud do bound-checking while copying instead of "hoping" that we'll
have enough room. In practice the 128k we allocate are largely enough
*/
err = (OSErr)copy_device_tree(devTree, outDevTreeSize, outDispRegOff);
if (err != noErr && (*outDevTreeSize > NAME_REGISTRY_MAX_SIZE)) {
dt_printf(dct, "#dev_tree: Device tree overflow ! Your machine is probably crashed now.¥n");
return err;
} else if (err != noErr) {
dt_printf(dct, "#dev_tree: Error %d while copying device tree !¥n", err);
}
return noErr;
}
OSErr
check_elf_kernel(boot_kernel_desc_t *in_desc)
{
OSErr err;
int i;
Elf32_Ehdr e;
Elf32_Phdr *p;
UInt32 total_file_size;
UInt32 offset, entry, load_loc;
UInt32 bootstraptask_offset = 0;
UInt32 size, ts, f_size;
char *t;
if (in_desc->file->rn == -1)
return notOpenErr;
offset = entry = size = f_size = 0;
total_file_size = in_desc->file->size;
ts = sizeof(Elf32_Ehdr);
err = file_read(in_desc->file, 0, &e, &ts);
if (err != noErr) {
dt_printf(dct, "#check_elf_kernel: can't read header, error %d¥n", err);
return err;
}
t = (char *) &e;
if (strncmp("MACH_BOOT_IMAGE", t, 15) == 0) {
char temp[32];
unsigned long a = 32;
err = file_read(in_desc->file, 0, temp, &a);
if (err != noErr) {
dt_printf(dct, "#check_elf_kernel: can't read Mach Kernel header, error %d¥n", err);
return err;
}
if (my_sscanfld(temp + 16, &bootstraptask_offset) != 1) {
dt_printf(dct, "#check_elf_kernel: can't read bootstrap task offset¥n");
return -1;
}
err = file_read(in_desc->file, a, &e, &ts);
}
/* Check if it is an executable elf binary. (Redudant but I like it this way)
*/
if (!(e.e_ident[EI_MAG0] == ELFMAG0 && e.e_ident[EI_MAG1] == ELFMAG1 &&
e.e_ident[EI_MAG2] == ELFMAG2 && e.e_ident[EI_MAG3] == ELFMAG3)) {
dt_printf(dct, "#check_elf_kernel: doesn't look like an ELF image !");
return -1;
}
if (e.e_ident[EI_CLASS] != ELFCLASS32
|| e.e_ident[EI_DATA] != ELFDATA2MSB) {
dt_printf(dct, "#check_elf_kernel: ELF image is wrong format (not PPC MSB 32) !");
return -1;
}
/* Check in the program header */
i = e.e_phnum;
/* compensate for eventual alignement */
while(i) {
ts = (sizeof(Elf32_Phdr)+4) * i;
if (ts > TEMP_BUFFER_SIZE) {
dt_printf(dct, "#skipping ELF section !¥n");
ts--;
} else
break;
}
if (ts == 0) {
dt_printf(dct, "#check_elf_kernel: skipped all sections !!!¥n");
return memFullErr;
}
err = file_read(in_desc->file, e.e_phoff + (bootstraptask_offset?32:0), s_temp_buffer, &ts);
if (err != noErr) {
dt_printf(dct, "#check_elf_kernel: error %d reading section headers !¥n");
return err;
}
p = (Elf32_Phdr *)(s_temp_buffer);
#define ADDRMASK 0x0fffffff
size = 0;
/* Scan through the program header
* HACK: We must return the _memory size of the kernel image, not the
* file size (because we have to leave room before other boot
* infos. This code works as a side effect of the fact that
* we have one section and vaddr == p_paddr
*/
for (i = 0; i < e.e_phnum; ++i, ++p) {
if (p->p_type != PT_LOAD || p->p_offset == 0)
continue;
if (size == 0) {
offset = p->p_offset;
size = p->p_memsz;
f_size = p->p_filesz;
load_loc = p->p_vaddr & ADDRMASK;
// dt_printf(dct, "size (1) : 0x%x¥n", size);
} else {
size = p->p_offset + p->p_memsz - offset; /* XXX Bogus */
f_size = p->p_offset + p->p_filesz - offset;
// dt_printf(dct, "size (2) : 0x%x¥n", size);
}
}
if (size == 0) {
dt_printf(dct, "#check_elf_kernel: Can't find a loadable segment !¥n");
return -1;
}
entry = (UInt32)(e.e_entry & ADDRMASK) - load_loc;
dt_printf(dct, "kernel memory size : %d bytes¥n", size);
dt_printf(dct, "kernel file offset : %d bytes¥n", offset);
dt_printf(dct, "kernel entry_offset : %d bytes¥n", entry);
in_desc->mem_size = size;
in_desc->size = f_size;
in_desc->offset = offset;
in_desc->entry = entry;
return 0;
out:
return -1;
}
/* Get the physical address, if possible, of a pointer. Note that
* we fail silently since we _do_ fail sometimes, like for screen
* base address. In this case, we just return the original pointer
*/
UInt8*
get_physical(void* ptr)
{
LogicalToPhysicalTable table;
unsigned long count;
OSErr err;
table.logical.address = ptr;
table.logical.count = 1024;
count = sizeof( table ) / sizeof( MemoryBlock ) - 1;
err = GetPhysical( &table, &count );
if ( err != noErr)
return ptr;
return (UInt8 *)(table.physical[0].address);
}
/* Make a portion of memory resident. */
OSErr
make_resident(void* ptr, unsigned long size, Boolean contiguous)
{
OSErr err;
if (size % g_page_size)
size = size + g_page_size - (size % g_page_size);
err = contiguous ? LockMemoryContiguous(ptr, size) : LockMemory(ptr, size);
bail:
if (err != noErr)
dt_printf(dct, "LockMemory%s failed, err: %d¥n",
contiguous ? "Contiguous" : "", err);
return err;
}
/* This function will build a simple map of the physical pages used
by the kernel stuffs
*/
OSErr
make_kernel_map(Ptr base, UInt32 total_size, UInt32 **out_map, UInt32 *out_size)
{
LogicalToPhysicalTable table;
unsigned long count, i;
OSErr err;
UInt32 page_count;
page_count = total_size / g_page_size;
*out_map = (UInt32 *)NewPtrClear((SInt32)(page_count * sizeof(UInt32)));
if (*out_map == NULL)
return memFullErr;
for (i=0; i<page_count; i++) {
/* First get all physical/logical mappings */
table.logical.address = base + i*g_page_size;
table.logical.count = 1024;
count = sizeof( table ) / sizeof( MemoryBlock ) - 1;
err = GetPhysical( &table, &count );
if ( err != noErr)
return err;
(*out_map)[i] = (UInt32)table.physical[0].address;
}
*out_size = page_count;
return noErr;
}
/* This function is used on non-PCI machines, it will look into some
internal MacOS NanoKernel data structures to figure out the physical
memory map of the machine */
void
build_memory_map(boot_infos_t* bi)
{
Ptr base = *((Ptr *)MACOS_MEMMAP_PTR_ADDR);
UInt32 len = *((UInt16 *)MACOS_MEMMAP_SIZE_ADDR);
UInt32 i;
if (len <= MACOS_MEMMAP_BANK_0FFSET)
return;
base += MACOS_MEMMAP_BANK_0FFSET;
len -= MACOS_MEMMAP_BANK_0FFSET;
i = 0;
while(len >= 8) {
UInt32 addr = *((UInt32*)base);
UInt32 size = *((UInt32*)(base+4));
if (size) {
if ((i>0) && ((bi->physMemoryMap[i-1].physAddr +
bi->physMemoryMap[i-1].size) == addr)) {
bi->physMemoryMap[i-1].size += size;
} else {
bi->physMemoryMap[i].physAddr = addr;
bi->physMemoryMap[i].size = size;
i++;
}
}
base += 8;
len -= 8;
}
bi->physMemoryMapSize = i;
}
void *
load_bootstrap(UInt32 mapSize, UInt32** outMapBegin,UInt32 *outTotalSize)
{
//#if BOOTX_ENV == BOOTX_ENV_RAW
// --- NOT YET IMPLEMENTED
//#else
Handle krsrc;
OSErr err;
CFragConnectionID fragID;
Ptr fragEntry, loc;
Str255 errStr;
UInt32 origSize, extOrigSize, newSize;
krsrc = GetResource('GLUE', code_boot_glueStrapPPC);
if (!krsrc) {
dt_printf(dct, "Can't load boostrap resource, err: %d¥n",
ResError());
goto error;
}
DetachResource(krsrc);
HUnlock(krsrc);
origSize = (UInt32)GetHandleSize(krsrc);
extOrigSize = origSize;
extOrigSize += 0x00000FFFUL;
extOrigSize &= 0xFFFFF000UL;
mapSize += 0x00000FFFUL;
mapSize &= 0xFFFFF000UL;
/* we add a page size */
newSize = extOrigSize + mapSize + g_page_size;
SetHandleSize(krsrc, (SInt32)newSize);
if (GetHandleSize(krsrc) != newSize) {
dt_printf(dct, "Can't resize boostrap, err: %d¥n",
MemError());
DisposeHandle(krsrc);
goto error;
}
HLock(krsrc);
loc = *krsrc;
loc = (Ptr)PAGE_ALIGN(loc);
if (loc != *krsrc) {
dt_printf(dct, "Boostrap moved from 0x%lx to 0x%lx¥n",
*krsrc, loc);
BlockMove(*krsrc, loc, (SInt32)origSize);
}
*outMapBegin = (UInt32*)(loc + extOrigSize);
*outTotalSize = newSize;
err = GetMemFragment(loc, origSize, "¥pbootstrap", kPrivateCFragCopy, &fragID, &fragEntry, errStr);
if (err != noErr) {
dt_printf(dct, "Boostrap preparation failed, err: %d (%#s)¥n",
err, errStr);
DisposeHandle(krsrc);
goto error;
}
return ((void **)fragEntry)[0];
error:
return NULL;
//#endif
}
#if BOOTX_USES_BUFPTR
/* This function allocates memory by moving down the BufPtr low memory globals. This
* is a special technique for use _only_ by system extensions that need a large amount
* that won't be available in the system heap. That's our case. The strange formula
* we use with MemTop comes from the MacOS historical roots, the system will make sure
* that MemTop has a correct value for this formula to apply.
* Note that this memory will be pageable.
*/
Ptr
alloc_high_mem(unsigned long count)
{
Ptr limit = (Ptr)((UInt32)LMGetMemTop()/2 + 1024);
Ptr bufPtr = LMGetBufPtr();
count += 256;
if ((bufPtr - limit) < count)
return NULL;
LMSetBufPtr(bufPtr - count);
bufPtr -= count;
return (Ptr)(((UInt32)bufPtr | 0xFFUL) + 1);
}
#endif // BOOTX_USES_BUFPTR
void
setup_basic_bootinfo(boot_infos_t* bi, UInt32 *out_load_base)
{
long response;
Boolean arch_pci;
OSErr err;
memset(bi, 0, sizeof(boot_infos_t));
bi->version = BOOT_INFO_VERSION;
bi->compatible_version = BOOT_INFO_COMPATIBLE_VERSION;
// Fill some fields of the boot_infos
err = Gestalt(gestaltMachineType, (long *)&bi->machineID);
if (err != noErr)
bi->machineID = 0;
bi->architecture = 0;
arch_pci = false;
if (Gestalt(gestaltOpenFirmwareInfo, &response) == noErr)
if (Gestalt(gestaltNameRegistryVersion, &response) == noErr)
arch_pci = true;
// Setup arch flags and memory map for NuBus
if (arch_pci) {
bi->architecture |= BOOT_ARCH_PCI;
*out_load_base = 0;
bi->physMemoryMapSize = 0;
} else {
build_memory_map(bi);
bi->architecture |= BOOT_ARCH_NUBUS;
/* FIXME: Should be smarter about finding a location */
*out_load_base = 0x200000;
switch(bi->machineID) {
case gestaltPowerMac6100_60:
case gestaltPowerMac6100_66:
case 101: /* gestaltPowerMac6100_80 */
case gestaltPowerMac7100_66:
case gestaltPowerMac7100_80:
case 113: /* gestaltPowerMac7100_80_chipped */
case gestaltPowerMac8100_80:
case gestaltPowerMac8100_100:
case gestaltPowerMac8100_110:
case gestaltPowerMac8100_120:
case gestaltAWS9150_80:
case gestaltAWS9150_120:
bi->architecture |= BOOT_ARCH_NUBUS_PDM;
break;
case gestaltPowerMac5200:
case gestaltPowerMac6200:
bi->architecture |= BOOT_ARCH_NUBUS_PERFORMA;
break;
case gestaltPowerBook1400:
case gestaltPowerBook5300:
case gestaltPowerBookDuo2300:
bi->architecture |= BOOT_ARCH_NUBUS_POWERBOOK;
break;
/* No default case, we let the kernel boot unsupported machines,
just in case... */
}
}
}
UInt32
get_temp_page(UInt32 *cur_temp, UInt32 *used_map, UInt32 used_size)
{
UInt32 page = *cur_temp;
UInt32 i;
again:
for (i=0; i<used_size; i++)
if (used_map[i] == page)
{
page += g_page_size;
goto again;
}
*cur_temp = page + g_page_size;
return page;
}
void
make_kernel_copymap(UInt32* map, UInt32 map_size, UInt32 *map_loc, UInt32 dest_base, UInt32 *temp_page)
{
UInt32 i,j,k;
dt_printf(dct, "Making kernel copy map...¥n");
k = 0;
for(i=0; i<map_size; i++) {
UInt32 src_page = map[i];
UInt32 dst_page = dest_base + (g_page_size * i);
if (src_page == dst_page)
continue;
/* Check if the destination overlaps a yet uncopied page */
for (j=i+1; j<map_size; j++) {
if (dst_page == map[j]) {
/* It overlaps. We add a "temp" copy of the dest page */
map_loc[k++] = dst_page;
map_loc[k++] = map[j] = get_temp_page(temp_page, map+i, map_size-i);
map_loc[k++] = g_page_size;
dt_printf(dct, "T 0x%08lx -> 0x%08lx¥n", map_loc[k-3], map_loc[k-2]);
break;
}
}
map_loc[k++] = src_page;
map_loc[k++] = dst_page;
map_loc[k++] = g_page_size;
}
map_loc[k++] = 0;
map_loc[k++] = 0;
map_loc[k++] = 0;
dt_printf(dct, "list of %d copies for %d pages¥n", ((k-1)/3), map_size);
}
#if BOOTX_ENV == BOOTX_ENV_APPLICATION
/* Send a restart event to the finder */
OSErr
send_restart_to_finder(void)
{
OSErr err = noErr;
ProcessSerialNumber sn;
AEDesc address;
AppleEvent theAE, reply;
err = find_finder_process(&sn);
if ( err == noErr ) err = AECreateDesc( typeProcessSerialNumber, &sn, sizeof( ProcessSerialNumber ), &address );
if ( err == noErr ) err = AECreateAppleEvent( kFinderSig, 'rest', &address, kAutoGenerateReturnID, kAnyTransactionID, &theAE);
if ( err == noErr ) err = AESend( &theAE, &reply, kAENoReply + kAECanInteract + kAECanSwitchLayer, kAENormalPriority, kAEDefaultTimeout, nil, nil );
return err;
}
/* We look for the Finder in the list of processes */
OSErr
find_finder_process(ProcessSerialNumberPtr processSN)
{
ProcessInfoRec tempInfo;
FSSpec procSpec;
Str31 processName;
OSErr myErr = noErr;
/* nul out the PSN so we're starting at the beginning of the list */
processSN->lowLongOfPSN = kNoProcess;
processSN->highLongOfPSN = kNoProcess;
/* initialize the process information record */
tempInfo.processInfoLength = sizeof(ProcessInfoRec);
tempInfo.processName = (unsigned char *)&processName;
tempInfo.processAppSpec = &procSpec;
/* loop through all the processes until we */
/* 1) find the process we want */
/* 2) error out because of some reason (usually, no more processes */
do {
myErr = GetNextProcess(processSN);
if (myErr == noErr)
GetProcessInformation(processSN, &tempInfo);
if ( tempInfo.processSignature == 'MACS' && tempInfo.processType == 'FNDR' )
break;
} while ( myErr == noErr );
return( myErr );
}
#endif // BOOTX_ENV == BOOTX_ENV_APPLICATION
OSErr
do_load_glues(Ptr *low_68k_glue, Ptr *low_PPC_glue)
{
Handle rsrc;
OSErr err;
// Just in case it was not the case
SetZone(SystemZone());
if (low_68k_glue) {
rsrc = Get1Resource('GLUE', code_boot_glue68k);
if (rsrc == NULL) {
err = ResError();
if (err == noErr) err = memFullErr;
return err;
}
HNoPurge(rsrc);
DetachResource(rsrc);
HLock(rsrc);
*low_68k_glue = *rsrc;
}
if (low_PPC_glue) {
rsrc = Get1Resource('GLUE', code_boot_gluePrePPC);
if (rsrc == NULL) {
err = ResError();
if (err == noErr) err = memFullErr;
return err;
}
HNoPurge(rsrc);
DetachResource(rsrc);
HLock(rsrc);
*low_PPC_glue = *rsrc;
}
return noErr;
}
void
add_l2cr_property(UInt32 l2cr_value)
{
RegEntryIter iterator;
RegEntryIterationOp operation;
OSStatus err;
Boolean done, found;
char buffer[1024];
RegEntryID root_node_id;
RegEntryID entryID;
Boolean first;
dt_printf(dct, "Setting L2CR override to 0x%08lx¥n", l2cr_value);
// Create an Iterator
operation = kRegIterContinue;
err = RegistryEntryIterateCreate(&iterator);
if (err != noErr) {
dt_printf(dct, " #Can't create iterator !¥n");
return;
}
err = RegistryEntryIDInit(&root_node_id);
if (err != noErr) {
dt_printf(dct, " #Can't init root id !¥n");
RegistryEntryIterateDispose(&iterator);
return;
}
err = RegistryCStrEntryLookup(NULL, "Devices:device-tree", &root_node_id);
if (err != noErr) {
dt_printf(dct, " #Can't find device tree root !¥n");
RegistryEntryIDDispose(&root_node_id);
RegistryEntryIterateDispose(&iterator);
return;
}
RegistryEntryIterateSet(&iterator, &root_node_id);
first = true;
found = false;
do {
RegPropertyValueSize size;
err = RegistryEntryIterate(&iterator, first ? kRegIterChildren : kRegIterContinue, &entryID, &done);
first = false;
if (!done && (err == noErr)) {
size = 1024;
err = RegistryPropertyGet(&entryID, "device_type", buffer, &size);
if (err == noErr) {
buffer[size] = 0;
dt_printf(dct, " -> type : %s¥n", buffer);
if ((strcmp(buffer, "cpus") == 0) || (strcmp(buffer, "cpu") == 0)) {
dt_printf(dct, " -> Found !¥n", buffer);
found = true;
err = RegistryPropertyCreate(&entryID, "l2cr-value", &l2cr_value, 4);
if (err != noErr) {
dt_printf(dct, " #Error %d creating property¥n", err);
}
break;
}
}
}
} while (!done && !found && (err == noErr));
RegistryEntryIterateDispose(&iterator);
RegistryEntryIDDispose(&root_node_id);
}
#if BOOTX_ENV != BOOTX_ENV_RAW
void
check_burgundy_patch(void)
{
Ptr patchPtr;
THz oldZone;
Handle patchRsrc;
oldZone = GetZone();
SetZone(SystemZone());
patchRsrc = Get1Resource('GLUE', code_boot_glueBurgundy);
if (patchRsrc == NULL) {
goto bail;
}
DetachResource(patchRsrc);
HLock(patchRsrc);
patchPtr = *patchRsrc;
if (!CallUniversalProc((RoutineDescriptor *)patchPtr,
kCStackBased | RESULT_SIZE(SIZE_CODE(sizeof(Boolean))))) {
HUnlock(patchRsrc);
DisposeHandle(patchRsrc);
}
bail:
SetZone(oldZone);
}
#endif // BOOTX_ENV != BOOTX_ENV_RAW
#pragma mark -
Boolean
check_kernel_file( boot_file_t *in_file,
boot_kernel_desc_t *out_kernel_infos,
boot_ramdisk_desc_t *out_ramdisk_infos,
Boolean *out_has_ramdisk)
{
Elf32_Ehdr *e;
struct external_filehdr* xc;
UInt32 size;
OSErr err;
*out_has_ramdisk = false;
out_kernel_infos->file = NULL;
out_ramdisk_infos->file = NULL;
/* Open kernel file */
err = file_open(in_file);
if (err != noErr) {
dt_printf(dct, "#check_kernel_file: file_open(%#s) returned %d¥n",
in_file->name, err);
return false;
}
/* Read first KB into buffer for header */
size = TEMP_BUFFER_SIZE;
err = file_read(in_file, 0, s_temp_buffer, &size);
if (err != noErr) {
dt_printf(dct, "#check_kernel_file: can't read first Kb of file (%#s), error %d¥n",
in_file->name , err);
goto fail;
}
/* Check if it is a Mach Kernel Image */
if (strncmp("MACH_BOOT_IMAGE", (char *) s_temp_buffer, 15) == 0) {
dt_printf(dct, "Found Mach Kernel Image (%#s)¥n", in_file->name);
out_kernel_infos->file = in_file;
out_kernel_infos->zImage = false;
/* These are filled later */
out_kernel_infos->offset = 0;
out_kernel_infos->size = 0;
out_kernel_infos->mem_size = 0;
out_kernel_infos->entry = 0;
out_kernel_infos->load_base = 0;
goto found;
}
e = (Elf32_Ehdr *)s_temp_buffer;
xc = (struct external_filehdr *)s_temp_buffer;
/* Check if it is an executable elf binary. */
if (e->e_ident[EI_MAG0] == ELFMAG0 && e->e_ident[EI_MAG1] == ELFMAG1 &&
e->e_ident[EI_MAG2] == ELFMAG2 && e->e_ident[EI_MAG3] == ELFMAG3) {
dt_printf(dct, "Found ELF kernel (%#s)¥n", in_file->name);
out_kernel_infos->file = in_file;
out_kernel_infos->zImage = false;
/* These are filled later */
out_kernel_infos->offset = 0;
out_kernel_infos->size = 0;
out_kernel_infos->mem_size = 0;
out_kernel_infos->entry = 0;
out_kernel_infos->load_base = 0;
goto found;
}
/* Check if this is an xcoff */
#define CHECK_MAGIC(xc,m) (get_16be(xc->f_magic) == (m))
if ((get_16be(xc->f_magic) == 0735) || (get_16be(xc->f_magic) == 0730)
|| (get_16be(xc->f_magic) == 0737)) {
struct external_scnhdr *sp;
struct external_scnhdr *isect, *rsect;
int ns, oh, i;
dt_printf(dct, "Found compressed XCOFF kernel (zImage : %#s)¥n", in_file->name);
out_kernel_infos->file = in_file;
out_kernel_infos->zImage = true;
/* These are filled later */
out_kernel_infos->mem_size = 0;
out_kernel_infos->entry = 0;
out_kernel_infos->load_base = 0;
ns = get_16be(xc->f_nscns);
oh = get_16be(xc->f_opthdr);
/* compensate for eventual alignement */
while(ns) {
size = (sizeof(struct external_scnhdr)+4) * ns;
if (size > TEMP_BUFFER_SIZE) {
dt_printf(dct, "#skipping section !¥n");
ns--;
} else
break;
}
if (ns == 0) {
dt_printf(dct, "#skipped all sections !!!¥n");
goto fail;
}
err = file_read(in_file, sizeof(struct external_filehdr) + oh, s_temp_buffer, &size);
if (err != noErr) {
dt_printf(dct, "#error %d while reading section headers !¥n");
goto fail;
}
sp = (struct external_scnhdr *) s_temp_buffer;
isect = rsect = NULL;
for (i = 0; i < ns; ++i, ++sp) {
dt_printf(dct, "section %d: %s¥n", i, sp->s_name);
if (strcmp(sp->s_name, "image") == 0)
isect = sp;
else if (strcmp(sp->s_name, "initrd") == 0)
rsect = sp;
}
if (isect == NULL) {
dt_printf(dct, "#image section not found¥n");
goto fail;
}
out_kernel_infos->offset = get_32be(isect->s_scnptr);
out_kernel_infos->size = get_32be(isect->s_size);
if (rsect != NULL) {
*out_has_ramdisk = true;
out_ramdisk_infos->file = in_file;
out_ramdisk_infos->offset = get_32be(rsect->s_scnptr);
out_ramdisk_infos->size = get_32be(rsect->s_size);
dt_printf(dct, "Ramdisk found in image, size: %dKb¥n",
(out_ramdisk_infos->size)/1024);
}
goto found;
}
fail: /* default */
file_close(in_file);
return false;
found:
file_close(in_file);
return true;
}
Boolean check_ramdisk_file( boot_file_t *in_file,
boot_ramdisk_desc_t *out_ramdisk_infos)
{
OSErr err;
/* Open kernel file */
err = file_open(in_file);
if (err != noErr) {
dt_printf(dct, "#check_ramdisk_file: file_open(%#s) returned %d¥n",
in_file->name, err);
return false;
}
out_ramdisk_infos->file = in_file;
out_ramdisk_infos->offset = 0;
out_ramdisk_infos->size = in_file->size;
file_close(in_file);
return true;
}
/* Some macros used by do_boot */
#if BOOTX_USES_BUFPTR
#define PREPARE_ALLOC() do {saveBufPtr = LMGetBufPtr(); } while(0)
#define FINISH_ALLOC() do {LMSetBufPtr(saveBufPtr); } while(0)
#define DO_ALLOC(sz) (alloc_high_mem(sz))
#define DO_FREE(p)
#else
#define PREPARE_ALLOC()
#define FINISH_ALLOC()
#define DO_ALLOC(sz) (NewPtrSys((SInt32)(sz)))
#define DO_FREE(p) do {THz _saveZone = GetZone(); SetZone(SystemZone()); ¥
DisposePtr(p); SetZone(_saveZone); } while(0)
#endif // BOOTX_USES_BUFPTR
#define ki in_kernel_infos
#define ri in_ramdisk_infos
OSStatus
do_boot( boot_kernel_desc_t *in_kernel_infos,
boot_ramdisk_desc_t *in_ramdisk_infos,
boot_params_t *in_params)
{
Ptr saveBufPtr = LMGetBufPtr();
Ptr big_stuffs;
OSStatus err;
UInt32 offsets[offset_count];
Ptr main_base, gzipped_kernel;
UInt32 total_size, ramdisk_size;
Ptr dev_tree;
UInt32 dev_tree_size;
UInt32 dev_tree_disp_off;
void* strap_entry;
UInt32 strap_phys_entry, strap_dest;
UInt32 boot_map_addr, strap_size;
UInt32 prec, args_len;
UInt32* map;
UInt32* map_loc;
UInt32 map_size, start, params;
UInt32 load_base, temp_page;
void* boot_glue_PPC;
boot_infos_t* bi;
Boolean resident;
Ptr low_68k_glue;
Ptr low_PPC_glue;
static PPCRegisterList regList;
PREPARE_ALLOC();
dev_tree = gzipped_kernel = big_stuffs = NULL;
low_68k_glue = NULL;
low_PPC_glue = NULL;
resident = false;
#if BOOTX_ENV == BOOTX_ENV_RAW
low_68k_glue = (Ptr)low_boot;
// low_PPC_glue = g_low_PPC_strap;
err = do_load_glues(NULL, &low_PPC_glue);
if (err != noErr) {
dt_printf(dct, "#do_boot: do_load_glues() failed with error %d¥n", err);
goto bail;
}
#else
err = do_load_glues(&low_68k_glue, &low_PPC_glue);
if (err != noErr) {
dt_printf(dct, "#do_boot: do_load_glues() failed with error %d¥n", err);
goto bail;
}
#endif
if (g_arch_PCI) {
/* Build the copy of the device tree */
dt_printf(dct, "Copying device tree...¥n");
dev_tree = DO_ALLOC(NAME_REGISTRY_MAX_SIZE);
if (dev_tree == NULL) {
dt_printf(dct, "#can't allocate room for device tree !¥n");
err = memFullErr;
goto bail;
}
if (in_params->override_l2cr)
add_l2cr_property(in_params->l2cr_value);
err = build_pci_device_tree(dev_tree, &dev_tree_size, &dev_tree_disp_off);
if (err != noErr) {
dt_printf(dct, "#build_pci_device_tree returned error %d¥n", err);
goto bail;
}
dt_printf(dct, "Device tree is %d bytes at 0x%lx¥n", dev_tree_size, dev_tree);
} else
dev_tree_size = 0;
/* Open the kernel file */
if (ki->file->rn == -1) {
err = file_open(ki->file);
if (err != noErr) {
dt_printf(dct, "#do_boot: file_open(%#s) returned %d¥n",
ki->file->name, err);
goto bail;
}
}
/* Open the ramdisk file */
if (ri && (ri->file->rn == -1)) {
err = file_open(ri->file);
if (err != noErr) {
dt_printf(dct, "#do_boot: file_open(%#s) returned %d¥n",
ri->file->name, err);
goto bail;
}
}
/* If we have a compressed kernel, we load it in a buffer and we use
an arbitrary memory size of 2*gz_size + 2Mb
*/
if (ki->zImage) {
UInt32 sz;
gzipped_kernel = DO_ALLOC(ki->size);
if (gzipped_kernel == NULL) {
dt_printf(dct, "#do_boot: can't allocate room for zImage¥n");
err = memFullErr;
goto bail;
}
sz = ki->size;
err = file_read(ki->file, ki->offset, gzipped_kernel, &sz);
if (err != noErr) {
dt_printf(dct, "#do_boot: file_read(%#s) returned %d¥n",
ki->file->name, err);
goto bail;
}
ki->mem_size = (ki->size * 2) + 0x100000;
} else {
err = check_elf_kernel(ki);
if (err != noErr) {
dt_printf(dct, "#do_boot: check_elf_kernel failed (err %d) !¥n", err);
goto bail;
}
}
/* Fix some values. */
if (ri == NULL)
ramdisk_size = 0;
else
ramdisk_size = ri->size;
if (in_params == NULL)
args_len = 0;
else
args_len = strlen(in_params->args)+1;
/* We build the map of offsets. */
offsets[offset_kernel] = 0;
offsets[offset_stack] = prec = PAGE_ALIGN(ki->mem_size);
offsets[offset_bootinfo] = prec = PAGE_ALIGN(prec + BOOT_KERNEL_STACK_SIZE);
offsets[offset_arguments] = prec = LINE_ALIGN(prec + sizeof(boot_infos_t));
offsets[offset_color_map] = prec = LINE_ALIGN(prec + args_len);
offsets[offset_device_tree] = prec = LINE_ALIGN(prec + BOOTX_COLORTABLE_SIZE);
offsets[offset_ramdisk] = prec = PAGE_ALIGN(prec + dev_tree_size);
prec = PAGE_ALIGN(prec + ramdisk_size);
total_size = prec + g_page_size;
/* We leave some room so that the unmangler won't erase itself */
offsets[offset_unmangler] = total_size + 2*g_page_size;
/* We do the final "big block" allocation */
big_stuffs = DO_ALLOC(total_size + g_page_size);
if (big_stuffs == NULL) {
dt_printf(dct, "#do_boot: can't allocate room for kernel¥n");
err = memFullErr;
goto bail;
}
main_base = (Ptr)PAGE_ALIGN(big_stuffs);
memset(main_base + offsets[offset_stack], 0, BOOT_KERNEL_STACK_SIZE);
dt_printf(dct, "Main stuffs base: 0x%x¥n", main_base);
/* Load or decompress kernel */
if (ki->zImage) {
unsigned int sz = (unsigned int)ki->mem_size;
dt_printf(dct, "Unzipping kernel... ¥n");
err = gunzip(main_base + offsets[offset_kernel], ki->mem_size,
(UInt8 *)gzipped_kernel, &sz);
if (err != noErr) {
dt_printf(dct, "#do_boot: gunzip failed !¥n");
goto bail;
}
dt_printf(dct, "Kernel using %dKb out of %dKb reserved¥n",
sz/1024, ki->mem_size/1024);
/* We can now free the temp buffer */
DO_FREE(gzipped_kernel);
gzipped_kernel = NULL;
} else {
UInt32 sz = ki->size;
err = file_read(ki->file, ki->offset, main_base + offsets[offset_kernel], &sz);
if (err != noErr) {
dt_printf(dct, "#do_boot: can't load ELF kernel image, err: %d¥n", err);
goto bail;
}
}
/* Fix kernel coff entry */
start = *(UInt32 *)(main_base + offsets[offset_kernel] + ki->entry);
if ((start < ki->load_base) || (start >= (ki->load_base + ki->mem_size))
|| (((UInt32 *)(main_base + offsets[offset_kernel] + ki->entry))[2] != 0))
/* doesn't look like a procedure descriptor */
start = ki->entry + ki->load_base;
ki->entry = start - ki->load_base;
dt_printf(dct, "Fixed kernel entry: 0x%x¥n", ki->entry);
/* We setup the boot-info stucture and fill it */
bi = (boot_infos_t *)(main_base + offsets[offset_bootinfo]);
setup_basic_bootinfo(bi, &load_base);
bi->totalParamsSize = BI_OFFSET(offset_unmangler);
if (args_len) {
bi->kernelParamsOffset = BI_OFFSET(offset_arguments);
memcpy(main_base + offsets[offset_arguments], in_params->args, args_len);
} else
bi->kernelParamsOffset = 0;
/* Make room for the colormap and store the offset. This offset will be used or cleared
when the display device infos are really gathered by the low-level booter */
bi->dispDeviceColorsOffset = BI_OFFSET(offset_color_map);
/* Copy in the device tree */
bi->deviceTreeOffset = BI_OFFSET(offset_device_tree);
bi->deviceTreeSize = dev_tree_size;
bi->dispDeviceRegEntryOffset = dev_tree_disp_off;
memcpy(main_base + offsets[offset_device_tree], dev_tree, dev_tree_size);
/* Copy the ramdisk */
if (ramdisk_size) {
UInt32 sz = ramdisk_size;
dt_printf(dct, "Loading ramdisk (%dKb)¥n", ramdisk_size/1024);
err = file_read(ri->file, ri->offset, main_base + offsets[offset_ramdisk], &sz);
if (err != noErr) {
dt_printf(dct, "#do_boot: can't load ramdisk, err: %d¥n", err);
goto bail;
}
bi->ramDisk = BI_OFFSET(offset_ramdisk);
bi->ramDiskSize = ramdisk_size;
}
#if BOOTX_ENV != BOOTX_ENV_RAW
/* First make all the stuff resident (but not necessarily contiguous) */
err = make_resident(main_base, total_size, in_params->no_relocation ? true : false);
if (err != noErr) {
dt_printf(dct, "#do_boot: can't make stuffs resident, err: %d¥n", err);
goto bail;
}
resident = true;
#endif // BOOTX_ENV != BOOTX_ENV_RAW
if (in_params->no_relocation) {
regList.PC = (UInt32)main_base + offsets[offset_kernel] + (UInt32)ki->entry;
regList.GPR[1] = (UInt32)main_base + offsets[offset_stack] + BOOT_KERNEL_STACK_SIZE - 512;
regList.GPR[2] = 0;
regList.GPR[3] = 'BooX';
regList.GPR[4] = (UInt32)main_base + offsets[offset_bootinfo];
regList.GPR[5] = 0;
} else {
/* Make a map of pages used by the kernel stuffs */
err = make_kernel_map(main_base, total_size, &map, &map_size);
if (err != noErr) {
dt_printf(dct, "Can't make kernel memory map, error %d¥n", err);
goto bail;
}
dt_printf(dct, "kernel map built, %d entries, loading bootsrap...¥n", map_size);
// the map size is multiplied by 2 to make room for "temp" copy
// operations that will be generated when source pages overlap
// destination. It's then multiplied by 12 which is the size of
// an entry in the copy-table.
strap_entry = load_bootstrap((map_size + 1) * 24, &map_loc, &strap_size);
if (!strap_entry) {
err = -1;
dt_printf(dct, "#do_boot: failed to bootstrap¥n");
goto bail;
}
#if BOOTX_ENV != BOOTX_ENV_RAW
// Make the boostrap resident and contiguous
err = make_resident(strap_entry, strap_size, true);
if (err != noErr) {
dt_printf(dct, "#do_boot: can't make bootstrap resident, err %d¥n", err);
goto bail;
}
#endif
// The boostrap will move itself just after the kernel.
strap_size = PAGE_ALIGN(strap_size);
strap_dest = load_base + offsets[offset_unmangler];
strap_phys_entry = (UInt32)get_physical(strap_entry);
// If the bootstrap destination overlaps a kenrel source page, we move
// it upward
do
{
int overlap = false;
int i;
for (i=0; i<map_size; i++)
if ((map[i] >= strap_dest)&&(map[i] < (strap_dest+strap_size))) {
overlap = true;
strap_dest += g_page_size;
dt_printf(dct, "strap overlap 0x%08lx -> 0x%08lx¥n", strap_dest - g_page_size, strap_dest);
break;
}
if (!overlap) {
// We also check if the boostrap destination overrides itself (source)
if ((strap_phys_entry < (strap_dest + strap_size)) &&
(strap_phys_entry > (strap_dest - strap_size))) {
strap_dest = PAGE_ALIGN(strap_phys_entry + strap_size);
dt_printf(dct, "strap overlap itself, -> 0x%08lx¥n", strap_dest);
} else
break;
}
} while(true);
offsets[offset_unmangler] = strap_dest - load_base;
boot_map_addr = strap_dest + (((UInt32)map_loc) - (UInt32)strap_entry);
temp_page = PAGE_ALIGN(strap_dest + strap_size);
dt_printf(dct, "strap entry : 0x%lx¥n", strap_entry);
dt_printf(dct, "strap dest : 0x%lx¥n", strap_dest);
dt_printf(dct, "strap phys entry : 0x%lx¥n", strap_phys_entry);
dt_printf(dct, "strap size : 0x%lx¥n", strap_size);
// Now, we build the page-copy list for the bootstrap. For each
// kernel page, we first check if the destination already holds
// a kernel page. If this is the case, then this page is copied
// to a temp buffer, the original copy is done, and the temp
// buffer is set to the original source
#if 1/*BOOTX_ENV != BOOTX_ENV_RAW*/
make_kernel_copymap(map, map_size, map_loc, load_base + offsets[offset_kernel], &temp_page);
dt_printf(dct, "last copy page dest : 0x%lx¥n", map_size * g_page_size);
#else
map_loc[0] = (UInt32)get_physical(main_base);
map_loc[1] = 0; /* g_load_base */
map_loc[2] = offsets[offset_unmangler];
map_loc[3] = 0;
map_loc[4] = 0;
map_loc[5] = 0;
#endif
DisposePtr((Ptr)map);
regList.PC = (unsigned long)strap_entry;
regList.GPR[1] = load_base + offsets[offset_stack] + BOOT_KERNEL_STACK_SIZE - 512; // The stack for the kernel entry
regList.GPR[2] = 1; // r2 flag must be set to 1 by BootX
regList.GPR[3] = 'BooX'; // r3 contains 'BooX' ($426F6F58)
regList.GPR[4] = load_base + offsets[offset_bootinfo]; // r4 contains the boot infos ptr
regList.GPR[5] = NULL; /*iMacHack;*/ // r5 NULL, replaced by low-bootsrap with map base of fb
regList.GPR[6] = strap_phys_entry; // r6 contains phys addr. of bootstrap
regList.GPR[7] = strap_dest; // r7 contains dest addr. of bootstrap
regList.GPR[8] = strap_size;
regList.GPR[9] = boot_map_addr;
regList.GPR[10] = ki->entry + load_base + offsets[offset_kernel];
regList.GPR[11] = 0;
}
// -- Call the low-level PPC boot glue (returns a pointer to an UPP) --
// this call will make sure the code fragment is prepared and returns a pointer
// that can later be called by the 68k code
#if TARGET_CPU_PPC
boot_glue_PPC = (void *)CallUniversalProc((RoutineDescriptor *)
low_PPC_glue, kPascalStackBased | RESULT_SIZE(SIZE_CODE(sizeof(void*))));
#else
boot_glue_PPC = ((pascal void*(*)(void))(low_PPC_glue))();
#endif
#if BOOTX_ENV != BOOTX_ENV_RAW
/* We try to patch the Burgundy driver to prevent it from shutting sound
down on iMac and BlueG3s */
dt_printf(dct, "Calling burgundy patch...¥n");
check_burgundy_patch();
#endif
err = noErr;
params = 0;
#if BOOTX_ENV == BOOTX_ENV_EXTENSION
if (in_params && in_params->setup_video)
params |= LOW_BOOT_SETUP_VIDEO;
#endif
if (in_params && in_params->force_scsi)
params |= LOW_BOOT_FORCE_SCSI_ON;
if (in_params && in_params->close_video)
params |= LOW_BOOT_CLOSE_VIDEO;
if (in_params && in_params->reset_ata)
params |= LOW_BOOT_RESET_ATA;
debug_checkpoint();
#if TARGET_CPU_PPC
dt_printf(dct, "Switching to 68k bootstrap...¥n");
CallUniversalProc((RoutineDescriptor *)low_68k_glue, uppLowLevelBoot68kProcInfo,
®List, bi, boot_glue_PPC, params, dct);
#else
dt_printf(dct, "Calling 68k bootstrap...¥n");
((pascal void(*)(PPCRegisterList*,boot_infos_t*,void*,UInt32,void*))(low_68k_glue))
(®List, bi, boot_glue_PPC, params, dct);
#endif
#if BOOTX_ENV == BOOTX_ENV_EXTENSION
dt_printf(dct, "Shutting machine down...¥n");
debug_checkpoint();
ShutDwnStart();
#elif BOOTX_ENV == BOOTX_ENV_APPLICATION
dt_printf(dct, "Sending restart event to Finder...¥n");
send_restart_to_finder();
#endif
bail:
if (err != noErr) {
if (big_stuffs)
DO_FREE(big_stuffs);
if (dev_tree)
DO_FREE(dev_tree);
if (gzipped_kernel)
DO_FREE(gzipped_kernel);
}
if (ki->file->rn != -1)
file_close(ki->file);
if (ri && ri->file->rn != -1)
file_close(ri->file);
FINISH_ALLOC();
return err;
}